package com.zzl.car.service;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.zzl.car.context.ZdpJwtUserContext;
import com.zzl.car.entity.CarDetailInfo;
import com.zzl.car.entity.CarOrder;
import com.zzl.car.exception.ZdpException;
import com.zzl.car.mapper.CarOrderMapper;
import com.zzl.car.util.ZtimeUtil;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
public class CarOrderService {
    @Autowired
    private CarOrderMapper carOrderMapper;
    @Autowired
    private CarDetailInfoService carDetailInfoService;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private InsuranceService insuranceService;
    /*
    * 分页
    * pageNum: 当前页码
    * nums: 一页显示多少条记录
    * 返回的订单疯转了车辆的详细信息和基础信息
    * 查询不同状态的订单
    * */
    public PageInfo<CarOrder> getAllOrderByUserAndPage(String telephone,int pageNum,int nums,Integer state){
        /*
        * status : -1 全部订单   0 预约中订单    1 租赁中订单    2 已完成订单   3 已取消订单
        * */
        /*
        * 除了 预约中和租赁中的订单，一般都不会改变  将订单存入缓存
        * （页面： 页面的订单id
        * 订单id：数据）
        * 算了直接将pageInfo 缓存进来吧 （x)
        * 页面：页面的订单号
        * 页面：pageInfo（不含数据的PageInfo）
        *
        * */
        PageInfo<CarOrder> pageInfo = null;
        List<CarOrder> carOrders = new ArrayList<>();
        //key : 页面数据的key ：页面有哪些订单id
        String pageNumKey = "carOrder-"+state.toString()+"-"+String.valueOf(pageNum)+"-"+telephone;
        String pageInfoKey = "carOrderPageInfo-"+state.toString()+"-"+String.valueOf(pageNum)+"-"+telephone;
        System.out.println(pageNumKey);
        System.out.println(pageInfoKey);
        if(redisTemplate.opsForList().size(pageNumKey)!=0){
          //获取 订单号
            List<String> orderNumbers = redisTemplate.opsForList().range(pageNumKey, 0, -1);
            //获取到PageInfo对象
            pageInfo =(PageInfo<CarOrder>) redisTemplate.opsForValue().get(pageInfoKey);
            //获取到CarOrder
            for(String carOrderKey : orderNumbers){
                CarOrder c =(CarOrder) redisTemplate.opsForValue().get(carOrderKey);
                carOrders.add(c);
            }
            pageInfo.setList(carOrders);
        }else{
            //缓存中没有 就从数据库中查询，然后存到缓存中
            PageHelper.startPage(pageNum,nums);
            if(state==-1){
                carOrders = carOrderMapper.getAllOrderByUser(telephone);
            }else{
                carOrders = carOrderMapper.getAllOrderByUserAndState(telephone,state);
            }
            for(int i=0;i<carOrders.size();i++){
                CarOrder carOrder = carOrders.get(i);
                //System.out.println(carOrder);
                //车辆详细信息和基础信息
                CarDetailInfo carDetailInfo = carDetailInfoService.getCarDetailInfoById(carOrder.getCarDetailInfoId());
                carOrder.setCarDetailInfo(carDetailInfo);
                // 保障服务信息
                if(carOrder.getInsuranceId()!=null){
                    carOrder.setInsurance(insuranceService.getInsuranceById(carOrder.getInsuranceId()));
                }
                //将订单信息存入缓存中，订单号作为key
                redisTemplate.opsForValue().set(carOrder.getOrderNumber(),carOrder,2,TimeUnit.HOURS);
                //将订单号存入缓存
                redisTemplate.opsForList().rightPush(pageNumKey,carOrder.getOrderNumber());
//            System.out.println(carOrders.get(i));
            }
            redisTemplate.expire(pageNumKey,2,TimeUnit.HOURS);
            pageInfo = new PageInfo<>(carOrders);
            //将pageInfo 存入缓存，不带list(数据） ：好蠢啊淦 郑达平的奇思妙想
            pageInfo.setList(null);
            redisTemplate.opsForValue().set(pageInfoKey,pageInfo,2,TimeUnit.HOURS);
            pageInfo.setList(carOrders);
        }
        return pageInfo;
    }

    /*
    * 根据订单号查看订单的详细信息
    * 先找缓存
    * 再找数据库表 ,会放车辆详细信息和保障服务信息
    * */
    public CarOrder getOrderByOrderNumber(String orderNumber){
        CarOrder carOrder =(CarOrder) redisTemplate.opsForValue().get(orderNumber);
        if(carOrder==null){
            carOrder = carOrderMapper.getOrderByOrderNumber(orderNumber);
            CarDetailInfo carDetailInfo = carDetailInfoService.getCarDetailInfoById(carOrder.getCarDetailInfoId());
            carOrder.setCarDetailInfo(carDetailInfo);
            if(carOrder.getInsuranceId()!=null){
                carOrder.setInsurance(insuranceService.getInsuranceById(carOrder.getInsuranceId()));
            }
            redisTemplate.opsForValue().set(orderNumber,carOrder,2,TimeUnit.HOURS);
        }
        return carOrder;
    }

    /*
    * 根据用户传入的信息生成订单
    * */
    public CarOrder createNewCarOrder(CarOrder carOrder){
        // 当前车辆状态改变
        carOrder.getCarDetailInfo().setState("1");
        //存入状态
        carOrder.setState(0);
        //存入用户
        carOrder.setUserTelephone(ZdpJwtUserContext.getCurrentName());
        //存入订单id
        Integer carOrderMaxId = carOrderMapper.getCarOrderMaxId();
        if(carOrderMaxId == null)
            carOrderMaxId = 0;
        carOrderMaxId++;
        carOrder.setId(carOrderMaxId);
        //生成订单号
        if(carOrder.getOrderNumber()==null){
            StringBuffer orderNum = new StringBuffer("zdp");
            for(int i=0;i<3;i++){
                System.out.println( ((int)( Math.random() * 10)));
                orderNum.append(((int)( Math.random() * 10)));
            }
            String s = carOrderMaxId.toString();
            for(int i=0;i<6-s.length();i++){
                orderNum.append(0);
            }
            orderNum.append(s);
            carOrder.setOrderNumber(orderNum.toString());
            // 创建订单
            Integer newCarOrder = carOrderMapper.createNewCarOrder(carOrder);
            if(newCarOrder==0){
                throw new ZdpException(1010,"订单创建失败");
            }
            //订单生成后，分页的缓存就需要修改，该用户的所有分页信息就要删除了
            Set<String> keys = redisTemplate.keys("carOrder*"+carOrder.getUserTelephone());
            redisTemplate.delete(keys);
            //将订单信息存入缓存
            redisTemplate.opsForValue().set(carOrder.getOrderNumber(),carOrder);
        }else{
            // 修改订单 修改订单要把之前订单的车辆信息修改了
            // 先获取到之前的订单信息
            CarOrder ctemp = getOrderByOrderNumber(carOrder.getOrderNumber());
            // 修改一下之前车辆的状态
            carDetailInfoService.updateCarStateByUser(0,ctemp.getCarDetailInfoId());
            carOrder = updateCarOrder(carOrder);
        }
        //更新当前选中车辆状态
        carDetailInfoService.updateCarStateByUser(1,carOrder.getCarDetailInfoId());

        //计算租期 前端算好了
       /* Double rent = ZtimeUtil.getTimeSubDayNoExactly(carOrder.getGetCarTime(),
                carOrder.getReturnCarTime());
        carOrder.setRent(rent);*/
        //生成订单
        // 判断是否有含保险
        /*if(carOrder.getInsuranceId()!=null){
            carOrderMapper.createNewCarOrder(carOrder);
        }else{
            carOrderMapper.createNewCarOrderNoInsurance(carOrder);
        }*/
        // 前端传来的数据包含有车辆的信息
       /* carOrder.setCarDetailInfo(carDetailInfoService.
                getCarDetailInfoById(carOrder.getCarDetailInfoId()));*/
        return carOrder;
    }

    /*
    * 获取到七天内的已完成的订单,拿到车辆的信息，通过消息队列传递
    * 消费者负责去查询违章记录
    * */
    public List<CarOrder> getCarOderInWeek(){
        //获取到当前的时间
        Timestamp timestamp = new Timestamp(System.currentTimeMillis());
        long tt = timestamp.getTime() - 7*24*60*60*1000;
        timestamp.setTime(tt);
        //查询一星期内状态为已完成的订单 state = 3
        List<CarOrder> carOrders = carOrderMapper.getCarOrderInWeek(timestamp, 3);
        //需要取到他们的车辆详细信息
        for(int i=0;i<carOrders.size();i++){
            CarOrder c = carOrders.get(i);
            c.setCarDetailInfo(carDetailInfoService.getCarPlateAndCarEngine(c.getCarDetailInfoId()));
        }
        return carOrders;
    }
    /*
    * 更新订单，缓存也需要更新
    * */
    public CarOrder updateCarOrder(CarOrder carOrder){
        Integer integer = carOrderMapper.updateCarOrder(carOrder);
        if(integer !=1){
          throw new ZdpException(1007,"订单修改失败");
        }
        // 更新缓存
        // 从数据库中查询新的 车辆基础保障服务 和保险服务
        carOrder.setCarDetailInfo(carDetailInfoService.getCarDetailInfoById(carOrder.getCarDetailInfoId()));
        carOrder.setInsurance(insuranceService.getInsuranceById(carOrder.getInsuranceId()));
        redisTemplate.opsForValue().set(carOrder.getOrderNumber(),carOrder);
        return carOrder;
    }
    /*
    * 取消预定中订单，只需要改变状态即可
    * */
    public CarOrder cancelCarOrderBooking(CarOrder carOrder){
        // 车辆状态也需要改变
        carDetailInfoService.updateCarStateByUser(0,carOrder.getCarDetailInfoId());
        Integer integer = carOrderMapper.updateCarOrder(carOrder);
        if(integer !=1){
            throw new ZdpException(1007,"订单取消失败");
        }
        // 更新缓存
        redisTemplate.opsForValue().set(carOrder.getOrderNumber(),carOrder);
        // 分页也要更新一下 ，就删除预定中和取消状态中的订单就行了
        Set<String> keys = redisTemplate.keys("carOrder*-[013]-*-"+carOrder.getUserTelephone());
        redisTemplate.delete(keys);
        return carOrder;
    }
    /*
    * 取消租赁中订单，改变状态，还需要记录退款的金额
    * */
    public CarOrder cancelCarOrderUsing(CarOrder carOrder, Date time){
        double returnMoney = 0;
        // 根据使用的天数来计算
        long times = time.getTime();
        long getTime = carOrder.getGetCarTime().getTime();
        long returnTime = carOrder.getReturnCarTime().getTime();
        if(times<=getTime){
            //扣除3%押金
            returnMoney = carOrder.getRent() + carOrder.getDeposit()*0.97;
        }else if(times<returnTime){
            // 计算使用了多少天
            double days = ZtimeUtil.getTimeSubDayNoExactly(getTime, times);
            double v = carOrder.getCarDetailInfo().getRent() * days;
            returnMoney = carOrder.getRent()-v +carOrder.getDeposit()*0.97;
        }else{
            double v = carOrder.getCarDetailInfo().getRent()*carOrder.getRentTime();
            returnMoney = carOrder.getRent() - v +carOrder.getDeposit()*0.97;
        }
        // 先修改，看有没有失败
        CarOrder result = cancelCarOrderBooking(carOrder);
        // 存放
        String key = "returnMoney-"+carOrder.getOrderNumber();
        redisTemplate.opsForValue().set(key,returnMoney);

        return result;
    }
    /*
    * 用户提前还车申请, 将用户的申请放到缓存中
    * */
    public void advanceReturnCar(String orderNumber,long time){
        // 将long 转为 日期
        Date tDate = new Date(time);
        String rDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(tDate);
        // 存到缓存中
        String key = "advanceReturnCar-"+orderNumber;
        redisTemplate.opsForValue().set(key,rDate);
    }

    /**
     *
     * @param orderNumber 订单号
     * @param time  新的还车时间
     *             续租需要计算用户需要另外支付的钱   40块钱一天的手续费
     */
    public void continueRentCar(String orderNumber,long time){
        // 获取到订单信息
        CarOrder carOrder = getOrderByOrderNumber(orderNumber);
        // 获取到订单的还车时间
        Long returnTime = carOrder.getReturnCarTime().getTime();
        // 得到相差的天数，计算用户还需支付的价格
        double days = ZtimeUtil.getTimeSubDayNoExactly(returnTime, time);
        double needPayMoney = days*carOrder.getCarDetailInfo().getRent() + days*40;
        // 将时间和 用户需要支付的价格存入到 redis
        Date tDate = new Date(time);
        String rDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(tDate);
        String key = "continueRentCar-"+orderNumber;
        // 存到redis数据库中
        Map<String,Object> map = new HashMap<>();
        map.put("returnTime",rDate);
        map.put("needPayMoney",needPayMoney);
        redisTemplate.opsForValue().set(key,map);
    }

    /*
    * 提前还车的申请
    * */
    public CarOrder getAdvanceReturningByUser(){
        CarOrder carOrder = null;
        String telephone = ZdpJwtUserContext.getCurrentName();
        String key = "WorkeradvReturnby-*-"+telephone;
        System.out.println(key);
        Set<String> keys = redisTemplate.keys(key);
        for(String k :keys){
            System.out.println("提前还车键");
            System.out.println(k);
            String s =(String) redisTemplate.opsForValue().get(k);
            if(s.equals("Yes")){
                // 说明申请通过了，获取到订单就可以返回了 记得删除该记录
                String orderNumber = k;
                orderNumber = orderNumber.split("-")[1];
                System.out.println("orderNumber");
                System.out.println(orderNumber);
                carOrder = getOrderByOrderNumber(orderNumber);
                redisTemplate.delete(k);
                break;
            }
            redisTemplate.delete(k);
        }
        System.out.println(carOrder);
        return carOrder;
    }

    /*
    * 续租申请轮询
    * */
    public CarOrder getContinueRentCarByUser(){
        return null;
    }
}
